%{

using namespace std;
#include "commun.h"

int dtdwrap(void);
void dtderror(DTD** root, char *msg);
int dtdlex(void);
extern FILE* dtdin;
%}

%union {
   char 		*s;
   string 		*str;
   int			i;
   Attribut 		*att;
   AttList 		*att_l;
   SimpleName 		*sn;
   ListSimpleName	*sn_l;
   Mixte 		*mx;
   ContentParticules 	*cp;
   Children		*child;
   DTDElement 		*dtd_el;
   CARDINALITY		card;
   DTD			*dtd;
   Choice		*cho;
   Sequence		*seq;
   ListCP		*lcp;
   
}

//%name-prefix "dtd" (définie dans makefile)
%parse-param {DTD **root}

%token ELEMENT ATTLIST CLOSE OPENPAR CLOSEPAR COMMA PIPE FIXED EMPTY ANY PCDATA AST QMARK PLUS CDATA
%token <s> IDENT TOKENTYPE DECLARATION STRING 
%type <str> att_type 
%type <str> default_declaration
%type <str> item_enum
%type <card> card_opt
%type <att> attribute
%type <att_l> att_definition_opt
%type <str> enum_list
%type <sn> simple_name
%type <sn_l> list_mixed
%type <mx> mixed
%type <cp> content_particules
%type <dtd_el> element_definition
%type <child> children
%type <dtd> main
%type <dtd> dtd_list_opt
%type <cho> choice
%type <seq> seq
%type <lcp> list_choice seq_cont_opt
%%

main
: dtd_list_opt {*root = $1; DBG("DTD lu\n");}
;

dtd_list_opt
: dtd_list_opt ATTLIST IDENT att_definition_opt CLOSE {$4->setName($3); $1->getAttList2().push_back($4); $$ = $1; DBG("AttributListe lu\n"); }
| dtd_list_opt ELEMENT IDENT element_definition CLOSE {$4->setName($3); $1->getElements2().push_back($4); $$ = $1; DBG("Element lu\n");}
| /* empty */ { $$ = new DTD();}
;

element_definition
: mixed					{ $$ = $1;}
| children				{ $$ = new DTDElement(E_CHILDREN); $$->setChildren($1); DBG("intEl : children\n");}
| ANY					{ $$ = new DTDElement(E_ANY); DBG("ANY\n");}
| EMPTY					{ $$ = new DTDElement(E_EMPTY); DBG("EMPTY\n");}
;

mixed
: OPENPAR PCDATA list_mixed CLOSEPAR /*AST*/	{ $$ = new Mixte(*$3); DBG("mixed lu avec card\n"); }
| OPENPAR PCDATA CLOSEPAR			{ list<SimpleName*> list; $$ = new Mixte(list); DBG("mixed (#PCDATA) lu\n"); }
;

list_mixed
: list_mixed PIPE simple_name		{ $$ = $1; $$->push_back($3); }
| PIPE simple_name			{ $$ = new list<SimpleName*>(); $$->push_back($2); }
;

simple_name
: IDENT					{ $$ = new SimpleName($1); free($1); }

;

content_particules
: children				{ $$ = $1; }
| IDENT card_opt			{ $$ = new Name($1, $2); free($1); }
;

children
: choice card_opt			{DBG("Choix suivit de card lu\n"); DBG("Dans children : %d\n", $2); $$ = $1; $$->setCardinality($2); }
| seq card_opt				{DBG("Seq suivit de card lu\n"); DBG("Dans children : %d\n", $2); $$ = $1; $$->setCardinality($2); }
;

choice
: OPENPAR content_particules list_choice CLOSEPAR	{$$ = new Choice(ONLY_ONE, *$3); $$->addParticuleFront($2);}
;

list_choice
: list_choice PIPE content_particules	{$$ = $1; $$->push_back($3);}
| PIPE content_particules		{$$ = new ListCP(); $$->push_back($2);}
;

seq
: OPENPAR content_particules seq_cont_opt CLOSEPAR	{$$ = new Sequence(ONLY_ONE, *$3); $$->addParticuleFront($2);}
;

seq_cont_opt
: seq_cont_opt COMMA content_particules	{$$ = $1; $$->push_back($3);}
| COMMA content_particules		{$$ = new ListCP(); $$->push_back($2);}
| /* vide */				{$$ = new ListCP(); }
;

card_opt
: PLUS					{ $$ = ONE_OR_MORE; }
| AST					{ $$ = ZERO_OR_MORE; }
| QMARK					{ $$ = OPTIONNAL; }
| /* vide */				{ $$ = ONLY_ONE; }
;

att_definition_opt
: att_definition_opt attribute		{ $$ = $1; $$->addAttribut($2);}
| /* empty */				{ $$ = new AttList(); }
;

attribute
: IDENT att_type default_declaration	{ $$ = new Attribut($1,"CDATA","#IMPLIED"); free($1);}
;

att_type /* Pas utilisé pour le sujet  #PCDATA #IMPLIED*/
: CDATA    				{ }
| TOKENTYPE				{ }
| enumerate				{ }
;

enumerate
: OPENPAR enum_list_plus CLOSEPAR
;

enum_list_plus
: enum_list PIPE item_enum
;

enum_list
: item_enum               
| enum_list PIPE item_enum
;

item_enum
: IDENT					{$$ = new string($1); free($1);}
;

default_declaration
: DECLARATION 				{ $$ = new string($1); free($1);}
| STRING     				{ $$ = new string($1); free($1); }
| FIXED STRING 				{ $$ = new string($2); free($2);}
;
%%

int dtdwrap(void)
{
  return 1;
}

void dtderror(DTD** root, char *msg)
{
  fprintf(stderr, "%s\n", msg);
}
